home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Applications / PICSee Dust 1.01 / Secondary Source / PICS_Composite.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-15  |  16.1 KB  |  576 lines  |  [TEXT/CWIE]

  1. #include "PICSDialogs.h"
  2. #include "PICSPreferencesDialog.h"
  3. #include "PICSCompositeDialog.h"
  4.  
  5. #include "PICS_Composite.h"
  6. #include "PICS_Operations.h"
  7. #include "PICS_Types.h"
  8. #include "PICS_Info.h"
  9. #include "PICS_Utils.h"
  10.  
  11. #include "Class_ProgressWindow.h"
  12. #include "FileRegistry.h"
  13. #include "CropPICTs.h"
  14. #include "StringUtils.h"
  15. #include "SavePicture.h"
  16.  
  17. #include "SimpleError.h"
  18. #include "assert_mac.h"
  19.  
  20. #include "main.h"            // For AppEmergencyUpdate()
  21.  
  22. #include "Monitors.h"        // For GetDeepestDevice(), etc.
  23. #include "QDUtils.h"        // For Set/HasMonitorDepth
  24. #include <QDOffscreen.h>
  25.  
  26. // ---------------------------------------------------------------------------
  27.  
  28. /*
  29.     This does the *actual* compositing.
  30.  
  31.     This is a real complicated bastard! Due to the fact that we
  32.     can crop or not crop, and assemble or not assemble, or a combo
  33.     of the previous. Also, the output format is different depending
  34.     on whether we assemble or not. If we do, the result is a composited
  35.     PICT file; if not then we're just cropping and the result is
  36.     a PICS file.
  37.     Add the fact that the input PICS format is complicated by the
  38.     usage of delta pictures! Makes me wanna cry...
  39. */
  40.  
  41. void CompositePICS(
  42.     CompositeOptions    *options,
  43.     FSSpec                *picsFile,
  44.     short                fileRefNum,
  45.     const Rect            *areaToCrop) {
  46.  
  47.     Boolean openedResFile = false;
  48.     short oldRefNum;
  49.  
  50.     ASSERT(options != NULL);
  51.     ASSERT(areaToCrop != NULL);
  52.  
  53.     AppEmergencyUpdate();
  54.  
  55.     oldRefNum = CurResFile();
  56.     if (picsFile != NULL && fileRefNum == -1) {
  57.         fileRefNum = FSpOpenResFile(picsFile, fsRdWrPerm);
  58.         if (!RegisterFile(fileRefNum)) {
  59.             UseResFile(oldRefNum);
  60.             SimpleError(kAlertErrID, kErrMsgID, kCantOpenFileErrMsg);
  61.             return;
  62.         }
  63.         openedResFile = true;
  64.     }
  65.  
  66.     if (fileRefNum == -1) {
  67.         SimpleError(kAlertErrID, kErrMsgID, kCantOpenFileErrMsg);
  68.         return;
  69.     }
  70.  
  71.     ProgressWindowPtr progressWindow;
  72.     GraphicsBufferPtr inputPictBuffer;
  73.     GraphicsBufferPtr outputCropBuffer;
  74.     Rect inputPictBounds;
  75.     Rect outputCropBounds;
  76.     Rect cropRect;
  77.     PicHandle inputPict;
  78.     GDHandle outputDevice;
  79.     GWorldPtr saveWorld;
  80.     GDHandle saveDev;
  81.     GBErr err;
  82.     short origDepth;
  83.     short numFrames;
  84.     short offsetH, offsetV;
  85.     PicHandle *outputPicts;
  86.     long picSize, largestPicSize;
  87.     PICSInfoRsrcHdl picsInfo;
  88.     short picDepth;
  89.  
  90.     SetCursor(*GetCursor(watchCursor));
  91.     UseResFile(fileRefNum);
  92.     
  93.     cropRect = *areaToCrop;
  94.  
  95.     numFrames = Count1Resources(kPICSRsrcType);
  96.     if (numFrames < 1) {
  97.         UseResFile(oldRefNum);
  98.         SimpleError(kAlertErrID, kErrMsgID, kNoPICTsInFileErrMsg);
  99.         if (openedResFile) {
  100.             (void)UnregisterFile(fileRefNum);
  101.             CloseResFile(fileRefNum);
  102.         }
  103.         return;
  104.     }
  105.  
  106.     if (options->frameStart == 0) {
  107.         options->frameStart = 1;    // Now set it to a valid index range
  108.         options->frameStop = numFrames;
  109.     }
  110.     
  111.     outputDevice = GetDeepestDevice();
  112.     origDepth = GetDeviceDepth(outputDevice);
  113.     progressWindow = new ProgressWindow(outputDevice,
  114.         (options->frameStop - options->frameStart + 1) + options->frameStart + 2);
  115.     SetPort(progressWindow->GetWindow());
  116.     TextFont(geneva);
  117.     TextSize(9);
  118.     TextFace(bold);
  119.  
  120.     inputPict = (PicHandle)Get1Resource(kPICSRsrcType, kPICSRsrcStartID);
  121.     if (inputPict == NULL) {
  122.         // No 'PICT's with an id of 128. Probably not a PICS file.
  123.         delete progressWindow;
  124.         UseResFile(oldRefNum);
  125.         SimpleError(kAlertErrID, kErrMsgID, kInvalidPICSFormatErrMsg);
  126.         if (openedResFile) {
  127.             (void)UnregisterFile(fileRefNum);
  128.             CloseResFile(fileRefNum);
  129.         }
  130.         return;
  131.     }
  132.     picDepth = GetPictDepth(inputPict);
  133.     if (options->outputDepthType == kUsePICSFileOutputDepth) {
  134.         options->outputDepth = picDepth;
  135.     }
  136.     inputPictBounds = (**inputPict).picFrame;
  137.     offsetH = inputPictBounds.left;
  138.     offsetV = inputPictBounds.top;
  139.     
  140.     picsInfo = GetPICSInfo();
  141.     if (picsInfo != NULL)
  142.         DetachResource((Handle)picsInfo);
  143.     
  144.     GetGWorld(&saveWorld, &saveDev);
  145.     progressWindow->SetPrimaryMessage("\pSetting up input buffer...");
  146.     progressWindow->Increment();
  147.     if (options->outputDepth == 0) {
  148.         CenterRect(&inputPictBounds, &(**outputDevice).gdRect);
  149.         err = NewGraphicsBuffer(&inputPictBuffer, 0,
  150.             (CP_Rect*)&inputPictBounds, kGBOptimalFlag, 0);
  151.     }
  152.     else {
  153.         FlushRectTopLeft(&inputPictBounds);
  154.         err = NewGraphicsBuffer(&inputPictBuffer, options->outputDepth,
  155.             (CP_Rect*)&inputPictBounds, kGBOptimalFlag, 0);
  156.     }
  157.     if (err != noErr) {
  158.         delete progressWindow;
  159.         UseResFile(oldRefNum);
  160.         SimpleError(kAlertErrID, kErrMsgID, kNoGWorldErrMsg);
  161.         if (openedResFile) {
  162.             (void)UnregisterFile(fileRefNum);
  163.             CloseResFile(fileRefNum);
  164.         }
  165.         return;
  166.     }
  167.     FlushRectTopLeft(&inputPictBounds);
  168.     
  169.     if (!options->doCrop) {
  170.         cropRect = inputPictBounds;
  171.         FlushRectTopLeft(&cropRect);
  172.     }
  173.  
  174.     if (options->doAssemble) {
  175.         progressWindow->SetPrimaryMessage("\pSetting up output buffer....");
  176.         progressWindow->Increment();
  177.  
  178.         outputCropBounds = cropRect;
  179.         FlushRectTopLeft(&outputCropBounds);
  180.  
  181.         if (options->assembleLeftToRight) {
  182.             outputCropBounds.right = outputCropBounds.right *
  183.                 (options->frameStop - options->frameStart + 1);
  184.         }
  185.         else {
  186.             outputCropBounds.bottom = outputCropBounds.bottom *
  187.                 (options->frameStop - options->frameStart + 1);
  188.         }
  189.         
  190.         if (options->outputDepth == 0) {
  191.             CenterRect(&outputCropBounds, &(**outputDevice).gdRect);
  192.             err = NewGraphicsBuffer(&outputCropBuffer, 0,
  193.                 (CP_Rect*)&outputCropBounds, kGBOptimalFlag, 0);
  194.         }
  195.         else {
  196.             FlushRectTopLeft(&outputCropBounds);
  197.             err = NewGraphicsBuffer(&outputCropBuffer, options->outputDepth,
  198.                 (CP_Rect*)&outputCropBounds, kGBOptimalFlag, 0);
  199.         }
  200.         if (err != noErr) {
  201.             delete progressWindow;
  202.             UseResFile(oldRefNum);
  203.             SimpleError(kAlertErrID, kErrMsgID, kNoGWorldErrMsg);
  204.             DisposeGraphicsBuffer(inputPictBuffer);
  205.             if (openedResFile) {
  206.                 (void)UnregisterFile(fileRefNum);
  207.                 CloseResFile(fileRefNum);
  208.             }
  209.             return;
  210.         }
  211.         FlushRectTopLeft(&outputCropBounds);
  212.     }
  213.     else {
  214.         outputPicts = (PicHandle*)NewPtr(sizeof(PicHandle) *
  215.             (options->frameStop - options->frameStart + 1));
  216.         outputCropBuffer = NULL;
  217.     }
  218.     
  219.     Rect srcCropRect, destCropRect;
  220.     Rect drawToRect, picFrame;
  221.  
  222.     srcCropRect = cropRect;
  223.     destCropRect = srcCropRect;
  224.     FlushRectTopLeft(&destCropRect);
  225.  
  226.     /*
  227.         Because of the possibility of delta pictures, regardless
  228.         of the frameStart parameter we have to
  229.         go through and draw each picture in the PICS starting at
  230.         the first one, id 128.
  231.     */
  232.     picSize = largestPicSize = 0;
  233.     short resID;
  234.     short frameCount = 0;        // 1 to number of frames we're working on
  235.     short endResID;
  236.     Str15 frameCountStr;
  237.  
  238.     // We need to calculate the last resource id we'll be using:
  239.     // The frame range starting resource id + the number of frames
  240.     // (NOT the starting resource id of 128, unless frameStart is 1!)
  241.     endResID = ((kPICSRsrcStartID + options->frameStart - 1)
  242.         + (options->frameStop - options->frameStart + 1));
  243.  
  244.     progressWindow->SetPrimaryMessage("\pSetting up frame:");
  245.     
  246.     for (resID = kPICSRsrcStartID; resID < endResID; resID++) {
  247.  
  248.         SetGWorld(saveWorld, saveDev);
  249.         if (resID == (kPICSRsrcStartID + options->frameStart - 1)) {
  250.             progressWindow->SetPrimaryMessage("\pCompositing frame:");
  251.         }
  252.         NumToString(resID - kPICSRsrcStartID + 1, frameCountStr); 
  253.         progressWindow->SetSecondaryMessage(frameCountStr);
  254.         progressWindow->Increment();
  255.  
  256.         /*
  257.             First step: load in 'PICT' frame
  258.         */
  259.         inputPict = (PicHandle)Get1Resource(kPICSRsrcType, resID);
  260.         
  261.         if (inputPict == NULL) {
  262.             delete progressWindow;
  263.             UseResFile(oldRefNum);
  264.             SimpleError(kAlertErrID, kErrMsgID, kUnableLoadPICTErrMsg);
  265.             DisposeGraphicsBuffer(inputPictBuffer);
  266.             if (options->doAssemble)
  267.                 DisposeGraphicsBuffer(outputCropBuffer);
  268.             else
  269.                 DisposePtr((Ptr)outputPicts);
  270.             if (openedResFile) {
  271.                 (void)UnregisterFile(fileRefNum);
  272.                 CloseResFile(fileRefNum);
  273.             }
  274.             return;
  275.         }
  276.         
  277.         /*
  278.             Second step: make sure we draw into inputPictBuffer
  279.             correctly (this includes adapting to possible
  280.             existence of delta pictures)
  281.         */
  282.         SetGraphicsBuffer(inputPictBuffer);
  283.         drawToRect = inputPictBounds;
  284.  
  285.         // Check for delta picture
  286.         if (resID > kPICSRsrcStartID) {
  287.             picFrame = (**inputPict).picFrame;
  288.  
  289.             // If first picture wasn't flushed topLeft (0,0), we
  290.             // have to do the same compensation here
  291.             OffsetRect(&picFrame, -offsetH, -offsetV);
  292.  
  293.             if (picFrame.left > drawToRect.left ||
  294.                 picFrame.top > drawToRect.top ||
  295.                 picFrame.right < drawToRect.right ||
  296.                 picFrame.bottom < drawToRect.bottom) {
  297.                 // Shucks! Delta pictures...
  298.                 drawToRect = picFrame;
  299.             }
  300.         }
  301.         /*
  302.             If it's a delta picture, we'll be drawing over the previous
  303.             frame (the desired action). And if it's not a delta
  304.             picture then this picture will completely overwrite the
  305.             previous one. So in either case we don't have to worry about
  306.             erasing the contents of <inputPictBuffer> before drawing.
  307.         */
  308.         DrawPicture(inputPict, &drawToRect);
  309.  
  310.         /*
  311.             Third step: do we crop only or assemble (with or without
  312.             cropping). We only do this if the picture is in the
  313.             specified frame range...
  314.             For assembling, determine compositing positions first.
  315.             Then crop during the composition if cropping is desired.
  316.             For cropping only, just capture the cropping process
  317.             to a new picture.
  318.         */
  319.         if (resID >= (kPICSRsrcStartID + options->frameStart - 1)) {
  320.  
  321.             if (options->doAssemble) {
  322.                 // OK, now to do the actual cropping and compositing
  323.                 FlushRectTopLeft(&destCropRect);
  324.                 if (options->assembleLeftToRight)
  325.                     OffsetRect(&destCropRect, destCropRect.right * frameCount, 0);
  326.                 else
  327.                     OffsetRect(&destCropRect, 0, destCropRect.bottom * frameCount);
  328.                 
  329.                 // Do the crop now
  330.                 CopyGraphicsBuffer(inputPictBuffer, outputCropBuffer,
  331.                     (CP_Rect*)&srcCropRect, (CP_Rect*)&destCropRect);
  332.                 
  333.             }
  334.             else {
  335.                 FlushRectTopLeft(&destCropRect);
  336.                 if (!CapturePICT(inputPictBuffer, inputPictBuffer,
  337.                     &srcCropRect, &destCropRect, &outputPicts[frameCount])) {
  338.                     UseResFile(oldRefNum);
  339.                     SimpleError(kAlertErrID, kErrMsgID, kUnexpectedErrMsg);
  340.                     ReleaseResource((Handle)inputPict);
  341.                     DisposeGraphicsBuffer(inputPictBuffer);
  342.                     DisposePtr((Ptr)outputPicts);
  343.                     if (openedResFile) {
  344.                         (void)UnregisterFile(fileRefNum);
  345.                         CloseResFile(fileRefNum);
  346.                     }
  347.                     return;
  348.                 }
  349.                 picSize = GetHandleSize((Handle)outputPicts[frameCount]);
  350.                 if (picSize > largestPicSize)
  351.                     largestPicSize = picSize;
  352.             }
  353.             
  354.             frameCount++;
  355.         }
  356.         
  357.         ReleaseResource((Handle)inputPict);
  358.     }
  359.  
  360.     SetGWorld(saveWorld, saveDev);
  361.     progressWindow->SetPrimaryMessage("\pDone.");
  362.     progressWindow->FinishProgress();
  363.     delete progressWindow;
  364.  
  365.     // So now we'll either have
  366.     //    a) array of Picture handles we'll have to save a PICT resources
  367.     //    b) one large composited graphicsBuffer we'll save as a PICT file
  368.     if (options->doAssemble) {
  369.         Str63 fileNameWithPrefix = kAssemblePrefix;
  370.         PicHandle outputPict;
  371.         WindowPtr previewWind;
  372.  
  373.         // Capture picture
  374.         if (!CapturePICT(outputCropBuffer, outputCropBuffer,
  375.             &outputCropBounds, &outputCropBounds, &outputPict)) {
  376.             UseResFile(oldRefNum);
  377.             SimpleError(kAlertErrID, kErrMsgID, kUnexpectedErrMsg);
  378.             DisposeGraphicsBuffer(inputPictBuffer);
  379.             DisposeGraphicsBuffer(outputCropBuffer);
  380.             if (openedResFile) {
  381.                 (void)UnregisterFile(fileRefNum);
  382.                 CloseResFile(fileRefNum);
  383.             }
  384.             return;
  385.         }
  386.         
  387.         PrefsHandle prefs = LoadPrefs();
  388.         if ((**prefs).compositePreview) {
  389.             AppEmergencyUpdate();
  390.  
  391.             CenterRect(&outputCropBounds, &(**outputDevice).gdRect);
  392.             previewWind = NewCWindow(NULL, &outputCropBounds, "\p ", false,
  393.                 plainDBox, (WindowPtr)-1, false, 0);
  394.             FlushRectTopLeft(&outputCropBounds);
  395.             ASSERT(previewWind != NULL);
  396.             
  397.             ShowWindow(previewWind);
  398.             SetPort(previewWind);
  399.             CopyGraphicsBuffer2Window(outputCropBuffer, previewWind,
  400.                 (CP_Rect*)&outputCropBounds, (CP_Rect*)&outputCropBounds);
  401.             
  402.             SetCursor(&qd.arrow);
  403.             EventRecord theEvent;
  404.             do {
  405.                 if (WaitNextEvent(everyEvent, &theEvent, 10, NULL)) {
  406.                     if (theEvent.what == mouseDown ||
  407.                         theEvent.what == keyDown)
  408.                         break;
  409.                 }
  410.             } while(true);
  411.             FlushEvents(everyEvent, 0);
  412.             HideWindow(previewWind);
  413.             DisposeWindow(previewWind);
  414.             AppEmergencyUpdate();
  415.         }
  416.         OSType pictCreatorType = (**prefs).pictCreatorType;
  417.         ReleaseResource((Handle)prefs);
  418.  
  419.         if (picsFile == NULL)
  420.             PStrCat("\pComposited PICT", fileNameWithPrefix);
  421.         else {
  422.             PStrCat(picsFile->name, fileNameWithPrefix);
  423.             PStrReplaceSuffix(kPICSSuffix, kPICTSuffix, fileNameWithPrefix);
  424.         }
  425.         if (fileNameWithPrefix[0] > 31)
  426.             fileNameWithPrefix[0] = 31;
  427.         SavePicture((Handle)outputPict, pictCreatorType, fileNameWithPrefix);
  428.  
  429.         KillPicture(outputPict);
  430.         DisposeGraphicsBuffer(outputCropBuffer);
  431.     }
  432.     else {
  433.         // Setup output PICS file
  434.         short outputFileRef;
  435.         StandardFileReply reply;
  436.         OSErr myErr;
  437.         Str63 fileNameWithPrefix = kCropPrefix;
  438.  
  439.         if (picsFile == NULL)
  440.             PStrCat("\pComposited PICS", fileNameWithPrefix);
  441.         else {
  442.             PStrCat(picsFile->name, fileNameWithPrefix);
  443.         }
  444.         if (fileNameWithPrefix[0] > 31)
  445.             fileNameWithPrefix[0] = 31;
  446.  
  447.         SetCursor(&qd.arrow);
  448.         StandardPutFile("\pSave cropped PICS file as:",
  449.             fileNameWithPrefix, &reply);
  450.  
  451.         AppEmergencyUpdate();
  452.  
  453.         if (reply.sfGood)  {
  454.             SetCursor(*GetCursor(watchCursor));
  455.  
  456.             // Determine creator type first.
  457.             OSType creatorTypePICS;
  458.             PrefsHandle prefs = LoadPrefs();
  459.             if ((**prefs).changeCreator) {
  460.                 // Change it to become one of our files...
  461.                 creatorTypePICS = kPICSiliciousCreatorType;
  462.             }
  463.             else {
  464.                 // Keep it's original creator type
  465.                 FInfo fileInfo;
  466.                 myErr = FSpGetFInfo(&reply.sfFile, &fileInfo);
  467.                 if (myErr == noErr) {
  468.                     creatorTypePICS = fileInfo.fdCreator;
  469.                 }
  470.                 else {
  471.                     creatorTypePICS = kPICSiliciousCreatorType;
  472.                 }
  473.             }
  474.             ReleaseResource((Handle)prefs);
  475.  
  476.             // Replace first if necessary
  477.             if (reply.sfReplacing) {
  478.                 myErr = FSpDelete(&reply.sfFile);
  479.                 if (myErr != noErr) {
  480.                 }
  481.             }
  482.  
  483.             FSpCreateResFile(&reply.sfFile, creatorTypePICS,
  484.                 kPICSFileType1, reply.sfScript);
  485.             myErr = ResError();
  486.             if (myErr != noErr)  {
  487.                 UseResFile(oldRefNum);
  488.                 SimpleError(kAlertErrID, kErrMsgID, kCantCreateFileErrMsg);
  489.                 DisposeGraphicsBuffer(inputPictBuffer);
  490.                 DisposePtr((Ptr)outputPicts);
  491.                 if (openedResFile) {
  492.                     (void)UnregisterFile(fileRefNum);
  493.                     CloseResFile(fileRefNum);
  494.                 }
  495.                 return;
  496.             }
  497.  
  498.             outputFileRef = FSpOpenResFile(&reply.sfFile, fsRdWrPerm);
  499.             if (outputFileRef == -1 || !RegisterFile(outputFileRef)) {
  500.                 UseResFile(oldRefNum);
  501.                 SimpleError(kAlertErrID, kErrMsgID, kCantOpenFileErrMsg);
  502.                 DisposeGraphicsBuffer(inputPictBuffer);
  503.                 DisposePtr((Ptr)outputPicts);
  504.                 if (openedResFile) {
  505.                     (void)UnregisterFile(fileRefNum);
  506.                     CloseResFile(fileRefNum);
  507.                 }
  508.                 return;
  509.             }
  510.  
  511.             progressWindow = new ProgressWindow(outputDevice,
  512.                 (options->frameStop - options->frameStart + 1));
  513.             SetPort(progressWindow->GetWindow());
  514.             TextFont(geneva);
  515.             TextSize(9);
  516.             TextFace(bold);
  517.             progressWindow->SetPrimaryMessage("\pSaving frame:");
  518.  
  519.             UseResFile(outputFileRef);
  520.             for (frameCount = 0, resID = kPICSRsrcStartID;
  521.                 frameCount < (options->frameStop - options->frameStart + 1);
  522.                 frameCount++, resID++) {
  523.  
  524.                 NumToString(options->frameStart+frameCount, frameCountStr);
  525.                 progressWindow->SetSecondaryMessage(frameCountStr);
  526.                 progressWindow->Increment();
  527.                 
  528.                 if (!SavePictureResource(outputPicts[frameCount], outputFileRef, resID, NULL)) {
  529.                 }
  530.                 KillPicture(outputPicts[frameCount]);
  531.             }
  532.             progressWindow->SetPrimaryMessage("\pDone.");
  533.             progressWindow->FinishProgress();
  534.             delete progressWindow;
  535.             
  536.             // --------------------------
  537.             // SAVE PICS INFO
  538.             // --------------------------
  539.             if (picsInfo == NULL) {
  540.                 // Create new 'INFO'
  541.                 picsInfo = NewPICSInfoResource();
  542.                 (**picsInfo).speed = kDefaultPICSSpeed;
  543.                 (**picsInfo).creatorType = kPICSiliciousCreatorType;
  544.             }
  545.             else {
  546.                 // Add detached 'INFO' from input file
  547.                 // to output file (& make it a resource)
  548.                 SavePICSInfo(picsInfo, false);
  549.             }
  550.             (**picsInfo).largestFrameSize = largestPicSize;
  551.             if (options->outputDepth == 0 || options->outputDepth > 32)
  552.                 (**picsInfo).depth = picDepth;
  553.             else
  554.                 (**picsInfo).depth = options->outputDepth;
  555.             if (!SavePICSInfo(picsInfo, true)) {
  556.                 // ERROR HANDLING
  557.             }
  558.             DisposePICSInfo(picsInfo);
  559.             
  560.             (void)UnregisterFile(outputFileRef);
  561.             CloseResFile(outputFileRef);
  562.         }
  563.         DisposePtr((Ptr)outputPicts);
  564.     }
  565.  
  566.     DisposeGraphicsBuffer(inputPictBuffer);
  567.  
  568.     // Close file only if we had opened it ourself
  569.     if (openedResFile) {
  570.         (void)UnregisterFile(fileRefNum);
  571.         CloseResFile(fileRefNum);
  572.     }
  573.     
  574.     UseResFile(oldRefNum);
  575.     SetCursor(&qd.arrow);
  576. } // END CompositePICS